<style scoped>
.tree-ew {
    cursor: ew-resize;
    position: absolute;
    top: 0;
    right: 0;
    width: 5px;
    height: 100%;
    background-color: #383838;
}

.tree {
    position: relative;
    width: 250px;
    height: 100%;
    padding-bottom: 10px;
}

.prop {
    position: relative;
    width: 320px;
    height: 100%;
    padding-bottom: 10px;
}

.node-hide {
    opacity: 0.3;
}
</style>

<template>
    <div style="display: flex; flex-direction: row; flex: 1;">
        <div class="tree" tabindex="0" @keyup="onKeyUp">
            <el-tree-v2 :height="height" :props="defaultProps" ref="treeRef"
                :default-expanded-keys="expandedKeys" empty-text="正在加载场景" :highlight-current="true"
                :expand-on-click-node="false" @node-expand="onNodeExpand" @node-collapse="onNodeCollapse"
                @current-change="onCurrentNodeChange">
                <template #default="{ node }">
                    <span :class="{ 'node-hide': !node.data.active }">{{ node.label }}</span>
                </template>
            </el-tree-v2>
            <div id="tree-ew" class="tree-ew"></div>
        </div>
        <div class="prop" tabindex="1" @keyup="onKeyUpH">
            <div :style="{ height: height, 'overflow-y': 'scroll', 'scrollbar-width': 'none'}">
                <TreeProp v-if="updateKey != 0 && isValid()" :node="currentNode" :update="updateKey" />
                <div id="prop-ew" class="tree-ew"></div>
            </div>
        </div>
    </div>
</template>

<script setup lang="ts">
import type { ElTreeV2, TreeNode, TreeNodeData } from 'element-plus';
import { onMounted, ref } from 'vue';
import TreeProp from './TreeProp.vue';

const defaultProps = {
    value: 'uuid',
    label: 'name',
}
//@ts-ignore
const isDev = process.env.NODE_ENV === 'development'
const height = window.innerHeight - 50
const treeRef = ref<InstanceType<typeof ElTreeV2>>()
let treeData: Array<CCTreeNode> = []
const expandedNodeMap = new Map();
let expandedKeys: string[] = [];
const updateKey = ref(1);
let currentNode: any = null

function isValid(){
    return (currentNode || isDev) && window.cc && cc.isValid(currentNode)
}

onMounted(() => {
    const intervalId = setInterval(() => {
        if (window.cc && cc.director.getScene()) {
            console.log('cc-inspector init');
            clearInterval(intervalId);
            refreshTree();
            resizeTree()
            resizeProp()
            window.addEventListener('keydown', (event: KeyboardEvent)=>{
                if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
                    event.preventDefault(); // 阻止默认的滚动行为
                }
            });
            //默认展开并选中Canvas
            for(let i=0; i<treeData.length; i++){
                if(treeData[i].name == 'Canvas'){
                    const tree = treeRef.value
                    const key = treeData[i].uuid
                    setTimeout(()=>{
                        const node = tree.getNode(key)
                        if(!node) return;
                        tree.expandNode(node)
                        // tree.setCurrentKey(key);
                        // const ccNode = getChildByUuidPath(cc.director.getScene(), node.data.path, 0);
                        // currentNode = ccNode;
                    }, 100)
                    break
                }
            }
        }
    }, 1000)
})

function resizeTree() {
    const handle: any = document.querySelector('#tree-ew');
    const container: any = document.querySelector('.tree');
    const width = localStorage.getItem('cc_tree_width')
    if(width) container.style.width = `${Number(width)}px`;

    let isDragging = false;
    handle.addEventListener('mousedown', (e: any) => {
        isDragging = true;
        const startX = e.clientX;
        const startWidth = container.offsetWidth;

        document.addEventListener('mousemove', onMouseMove);
        document.addEventListener('mouseup', onMouseUp);

        function onMouseMove(e: any) {
            if (isDragging) {
                const deltaX = e.clientX - startX;
                container.style.width = `${startWidth + deltaX}px`;
            }
        }

        function onMouseUp(e: any) {
            isDragging = false;
            document.removeEventListener('mousemove', onMouseMove);
            document.removeEventListener('mouseup', onMouseUp);
            const width = e.clientX - startX + startWidth
            localStorage.setItem('cc_tree_width', width)
        }
    });
}
function resizeProp() {
    const handle: any = document.querySelector('#prop-ew');
    const container: any = document.querySelector('.prop');
    const width = localStorage.getItem('cc_prop_width')
    if(width) container.style.width = `${Number(width)}px`;

    let isDragging = false;
    handle.addEventListener('mousedown', (e: any) => {
        isDragging = true;
        const startX = e.clientX;
        const startWidth = container.offsetWidth;

        document.addEventListener('mousemove', onMouseMove);
        document.addEventListener('mouseup', onMouseUp);

        function onMouseMove(e: any) {
            if (isDragging) {
                const deltaX = e.clientX - startX;
                container.style.width = `${startWidth + deltaX}px`;
            }
        }

        function onMouseUp(e: any) {
            isDragging = false;
            document.removeEventListener('mousemove', onMouseMove);
            document.removeEventListener('mouseup', onMouseUp);
            const width = e.clientX - startX + startWidth
            localStorage.setItem('cc_prop_width', width)
        }
    });
}

function refreshTree() {
    if (window.ccdevShow) {
        let value: CCTreeNode[] = [];
        getChildren(value, cc.director.getScene().children, []);
        treeData = value
        treeRef.value.setData(value);
        updateKey.value = -updateKey.value;
    }
    window.requestAnimationFrame(refreshTree);
}

function getChildren(container: CCTreeNode[], children: any[], path: string[]) {
    children.forEach(ccNode => {
        const childPath = path.concat(ccNode.uuid);
        const node = {
            uuid: ccNode.uuid,
            name: ccNode.name,
            active: ccNode.activeInHierarchy,
            children: [] as CCTreeNode[],
            path: childPath,
        };
        if (ccNode.children && ccNode.children.length > 0) {
            getChildren(node.children, ccNode.children, childPath);
        }
        container.push(node);
    });
}

function onNodeExpand(data: TreeNodeData, node: TreeNode) {
    expandedNodeMap.set(data.uuid, true);
    expandedKeys = [...expandedNodeMap.keys()];
}

function onNodeCollapse(data: TreeNodeData, node: TreeNode) {
    expandedNodeMap.delete(data.uuid);
    expandedKeys = [...expandedNodeMap.keys()];
}

function onCurrentNodeChange(data: TreeNodeData, node: TreeNode) {
    // console.log('onCurrentNodeChange', data, node)
    if (data) {
        const ccNode = getChildByUuidPath(cc.director.getScene(), data.path, 0);
        currentNode = ccNode;
    } else {
        currentNode = null;
    }
}

function onKeyUp(event: KeyboardEvent){
    if (!window.ccdevShow) return;
    const tree = treeRef.value;
    if (!tree) return;
    const key = tree.getCurrentKey()
    if (!key) return;
    const node = tree.getNode(key)
    if (!node) return;
    const data = node.data as CCTreeNode

    if (event.key === 'ArrowDown') {
        event.preventDefault();
        const key = getNextNode(node)
        if (key){
            tree.setCurrentKey(key);
            const ccNode = getChildByUuidPath(cc.director.getScene(), tree.getNode(key).data.path, 0);
            currentNode = ccNode;
        }
    }
    else if (event.key === 'ArrowUp') {
        event.preventDefault();
        const key = getPrevNode(tree, node)
        if (key){
            tree.setCurrentKey(key);
            const ccNode = getChildByUuidPath(cc.director.getScene(), tree.getNode(key).data.path, 0);
            currentNode = ccNode;
        }
    }
    else if (event.key === 'ArrowRight') {
        if (node.children && !expandedNodeMap.get(data.uuid))
            tree.expandNode(node);
        else if (node.children) {
            let key;
            for (let i = 0; i < node.children.length; i++) {
                if (node.children[i].children) {
                    key = node.children[i].key
                    break
                }
            }
            if (key){
                tree.setCurrentKey(key);
                const ccNode = getChildByUuidPath(cc.director.getScene(), tree.getNode(key).data.path, 0);
                currentNode = ccNode;
            }
        }
    }
    else if (event.key === 'ArrowLeft') {
        if (node.children && expandedNodeMap.get(data.uuid))
            tree.collapseNode(node);
        else if (node.parent){
            tree.setCurrentKey(node.parent.key);
            const ccNode = getChildByUuidPath(cc.director.getScene(), tree.getNode(node.parent.key).data.path, 0);
            currentNode = ccNode;
        }
    }
    else if(event.key === 'h'){
        currentNode.active = !currentNode.active
    }
}

function onKeyUpH(event: KeyboardEvent){
    if(event.key === 'h'){
        if(currentNode)
            currentNode.active = !currentNode.active
    }
}

function getNextNode(node: TreeNodeData) {
    const data = node.data as CCTreeNode
    if (expandedNodeMap.get(node.key) && data.children.length > 0) {
        return data.children[0].uuid
    }
    else {
        let curSelect = node
        while (curSelect.parent) {
            let children = curSelect.parent.children
            if (children && children.length > 0) {
                const index = children.indexOf(curSelect)
                if (children[index + 1]) {
                    return children[index + 1].key
                }
                else curSelect = curSelect.parent;
            }
        }
        const index = treeData.indexOf(curSelect.data)
        if (treeData[index + 1])
            return treeData[index + 1].uuid
        else
            return treeData[0].uuid
    }
}

function getPrevNode(tree: InstanceType<typeof ElTreeV2>, node: TreeNodeData) {
    let curSelect = node
    if (curSelect.parent) {
        let children = curSelect.parent.children
        const index = children.indexOf(curSelect)
        if (children[index - 1])
            curSelect = children[index - 1]
        else {
            curSelect = curSelect.parent
            return curSelect.key
        }
    }
    else {
        const index = treeData.indexOf(curSelect.data)
        if (treeData[index - 1])
            curSelect = tree.getNode(treeData[index - 1].uuid)
        else
            curSelect = tree.getNode(treeData[treeData.length - 1].uuid)
    }
    while (expandedNodeMap.get(curSelect.key)) {
        curSelect = curSelect.children[curSelect.children.length - 1]
    }
    return curSelect.key
}

function getChildByUuidPath(node: any, path: string[], index: number): any {
    if (index >= path.length) {
        return node;
    }
    node = node.getChildByUuid(path[index]);
    return getChildByUuidPath(node, path, index + 1);
}
</script>